package com.iris.thread.volatileTest;

/**
 * 项目: thinking
 * 包名: com.iris.thread.volatileTest
 * 作者: victor
 * 日期: 2016年10月31日
 * 说明: VolatileTest
 * 
 * 在当前的Java内存模型下，线程可以把变量保存在本地内存（比如机器的寄存器）中，而不是直接在主存中进行读写。
 * 这就可能造成一个线程在主存中修改了一个变量的值，而另外一个线程还继续使用它在寄存器中的变量值的拷贝，造成数据的不一致。
 * ==========================
 * 经过测试不加Volatile引起的线程不能立刻读到变化数据的情况,需要很严苛的条件,大部分条件下是能直接读取变化后的数据的
 * 具体解释:
 * 在JDK1.7~JDK1.3之间的版本上输出结果与上面基本大同小异，只有在JDK1.2上才得到了预期的结果，
 * 对于非volatile修饰的变量，尽管jvm的优化，会导致变量的可见性问题，但这种可见性的问题也只是在短时间内高并发的情况下发生，
 * CPU执行时会很快刷新Cache，一般的情况下很难出现，而且出现这种问题是不可预测的，与jvm, 机器配置环境等都有关。
 * 所以在未修改flag1之前，i会一直自增。一旦flag1修改后，sleep了1s,在flag2为修改之前，while循环就退出了，所以基本不会看到输出。
 */
public class VolatileTest {
	public static void main(String[] args) {
		VolatileRunnable vr = new VolatileRunnable();
		Thread th=new Thread(vr);

		System.out.println("Main====begin");
		th.start();
		try {
			Thread.sleep(1000);//保证开始运行run
			//测试volatile变量
			System.out.println("Main====setVolatileVar");
			vr.setVolatileVar(10);
			System.out.println("Main====setVolatileVar===end");
			//先测试普通变量
			
			System.out.println("Main====setNormalVar");
			vr.setNormalVar(10);
			System.out.println("Main====setNormalVar===end");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}


class VolatileRunnable implements Runnable{
	private int normalVar=0;
	private volatile int volatileVar=0;
	
	public int getNormalVar() {
		return normalVar;
	}

	public void setNormalVar(int normalVar) {
		this.normalVar = normalVar;
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public int getVolatileVar() {
		return volatileVar;
	}

	public void setVolatileVar(int volatileVar) {
		this.volatileVar = volatileVar;
		try {
			Thread.sleep(1000);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}

	public void run() {
		System.out.println("VolatileRunnable====begin");
		while(normalVar<1){
//			System.out.println("VolatileRunnable====normalVar");
			while(volatileVar>1){
				System.out.println("VolatileRunnable====volatileVar===return");
				return;
			}
		}
		System.out.println("VolatileRunnable====end");
	}
	
}